Spring Security Web 5.1.2 源码解析 -- SecurityContextHolderAwareRequestFilter

概述

SecurityContextHolderAwareRequestFilter对请求HttpServletRequest采用Wrapper/Decorator模式包装成一个可以访问SecurityContextHolder中安全上下文的SecurityContextHolderAwareRequestWrapper。这样接口HttpServletRequest上定义的getUserPrincipal这种安全相关的方法才能访问到相应的安全信息。

针对Servlet 2.5Servlet 3,该过滤器使用了不一样的工厂,但最终都是使用SecurityContextHolderAwareRequestWrapper封装请求使其具备访问SecurityContextHolder安全上下文的能力。

源代码解析

package org.springframework.security.web.servletapi;

import java.io.IOException;
import java.util.List;

import javax.servlet.AsyncContext;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.web.filter.GenericFilterBean;

public class SecurityContextHolderAwareRequestFilter extends GenericFilterBean {
	// ~ Instance fields
	// ====================================================================================

	// 缺省角色名称的前缀
	private String rolePrefix = "ROLE_";

	// 用于封装HttpServletRequest的工厂类,最终目的是封装HttpServletRequest
	// 使之具有访问SecurityContextHolder中安全上下文的能力。
	// 针对 Servlet 2.5 和 Servlet 3 使用的不同实现类。
	private HttpServletRequestFactory requestFactory;

	private AuthenticationEntryPoint authenticationEntryPoint;

	private AuthenticationManager authenticationManager;

	private List<LogoutHandler> logoutHandlers;

	// 判断认证对象Authentication是何种类型:是否匿名Authentication,
	// 是否 Remember Me Authentication。
	// 缺省使用实现AuthenticationTrustResolverImpl,
	// 根据对象Authentication所使用的实现类是AnonymousAuthenticationToken
	// 还是RememberMeAuthenticationToken达到上述目的
	private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();

	// ~ Methods
	// ====================================================================================
	// 指定角色前缀,
	public void setRolePrefix(String rolePrefix) {
		Assert.notNull(rolePrefix, "Role prefix must not be null");
		this.rolePrefix = rolePrefix;
		// 角色前缀变更时更新requestFactory工厂
		updateFactory();
	}

	/**
	 * 
	 * Sets the  AuthenticationEntryPoint used when integrating
	 * HttpServletRequest with Servlet 3 APIs. Specifically, it will be used when
	 * HttpServletRequest#authenticate(HttpServletResponse) is called and the user
	 * is not authenticated.
	 * 
	 * 
	 * If the value is null (default), then the default container behavior will be be
	 * retained when invoking HttpServletRequest#authenticate(HttpServletResponse)
	 * .
	 * 
	 *
	 * @param authenticationEntryPoint the AuthenticationEntryPoint to use when
	 * invoking HttpServletRequest#authenticate(HttpServletResponse) if the user
	 * is not authenticated.
	 *
	 * @throws IllegalStateException if the Servlet 3 APIs are not found on the classpath
	 */
	public void setAuthenticationEntryPoint(
			AuthenticationEntryPoint authenticationEntryPoint) {
		this.authenticationEntryPoint = authenticationEntryPoint;
	}

	/**
	 * 
	 * Sets the AuthenticationManager used when integrating
	 *  HttpServletRequest with Servlet 3 APIs. Specifically, it will be used when
	 *  HttpServletRequest#login(String, String) is invoked to determine if the
	 * user is authenticated.
	 * 
	 * 
	 * If the value is null (default), then the default container behavior will be
	 * retained when invoking  HttpServletRequest#login(String, String).
	 * 
	 *
	 * @param authenticationManager the AuthenticationManager to use when invoking
	 * HttpServletRequest#login(String, String)
	 *
	 * @throws IllegalStateException if the Servlet 3 APIs are not found on the classpath
	 */
	public void setAuthenticationManager(AuthenticationManager authenticationManager) {
		this.authenticationManager = authenticationManager;
	}

	/**
	 *
	 * Sets the LogoutHandlers used when integrating with
	 * HttpServletRequest with Servlet 3 APIs. Specifically it will be used when
	 * HttpServletRequest#logout() is invoked in order to log the user out. So
	 * long as the LogoutHandlers do not commit the  HttpServletResponse
	 * (expected), then the user is in charge of handling the response.
	 * 
	 * 
	 * If the value is null (default), the default container behavior will be retained
	 * when invoking HttpServletRequest#logout().
	 * 
	 *
	 * @param logoutHandlers the Lis<LogoutHandler> when invoking
	 * HttpServletRequest#logout().
	 *
	 * @throws IllegalStateException if the Servlet 3 APIs are not found on the classpath
	 */
	public void setLogoutHandlers(List<LogoutHandler> logoutHandlers) {
		this.logoutHandlers = logoutHandlers;
	}

	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
			throws IOException, ServletException {
		chain.doFilter(this.requestFactory.create((HttpServletRequest) req,
				(HttpServletResponse) res), res);
	}

	@Override
	public void afterPropertiesSet() throws ServletException {
	// 本Filter因为继承自GenericFilterBean,从而隐含地实现了接口InitializingBean,
	// 所以会有此方法。而此方法会在该Filter bean被初始化时调用。此时会确定具体使用的
	// requestFactory 实例
		super.afterPropertiesSet();
		updateFactory();
	}

	private void updateFactory() {
		// 更新封装HttpServletRequest的工厂实例requestFactory,
		// 根据当前使用的Servlet版本的不同使用不同的工厂类
		String rolePrefix = this.rolePrefix;
		this.requestFactory = isServlet3() ? createServlet3Factory(rolePrefix)
				: new HttpServlet25RequestFactory(this.trustResolver, rolePrefix);
	}

	/**
	 * Sets the AuthenticationTrustResolver to be used. The default is
	 * AuthenticationTrustResolverImpl.
	 *
	 * @param trustResolver the AuthenticationTrustResolver to use. Cannot be
	 * null.
	 */
	public void setTrustResolver(AuthenticationTrustResolver trustResolver) {
		Assert.notNull(trustResolver, "trustResolver cannot be null");
		this.trustResolver = trustResolver;
		// trustResolver 变更时更新requestFactory工厂
		updateFactory();
	}

	private HttpServletRequestFactory createServlet3Factory(String rolePrefix) {
		HttpServlet3RequestFactory factory = new HttpServlet3RequestFactory(rolePrefix);
		factory.setTrustResolver(this.trustResolver);
		factory.setAuthenticationEntryPoint(this.authenticationEntryPoint);
		factory.setAuthenticationManager(this.authenticationManager);
		factory.setLogoutHandlers(this.logoutHandlers);
		return factory;
	}

	/**
	 * Returns true if the Servlet 3 APIs are detected.
	 * @return
	 */
	private boolean isServlet3() {
		return ClassUtils.hasMethod(ServletRequest.class, "startAsync");
	}
}

其他文章

Spring Security Web 5.1.2 源码解析 – 安全相关Filter清单

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值